home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / tcsh / dist / glob.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-21  |  15.7 KB  |  659 lines

  1. /*
  2.  * Copyright (c) 1989 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Guido van Rossum.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36. #if defined(LIBC_SCCS) && !defined(lint)
  37. static char sccsid[] = "@(#)glob.c    5.12 (Berkeley) 6/24/91";
  38. #endif /* LIBC_SCCS and not lint */
  39. /*
  40.  * Glob: the interface is a superset of the one defined in POSIX 1003.2,
  41.  * draft 9.
  42.  *
  43.  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
  44.  *
  45.  * Optional extra services, controlled by flags not defined by POSIX:
  46.  *
  47.  * GLOB_QUOTE:
  48.  *    Escaping convention: \ inhibits any special meaning the following
  49.  *    character might have (except \ at end of string is retained).
  50.  * GLOB_MAGCHAR:
  51.  *    Set in gl_flags if pattern contained a globbing character.
  52.  * GLOB_ALTNOT:
  53.  *    Use ^ instead of ! for "not".
  54.  * gl_matchc:
  55.  *    Number of matches in the current invocation of glob.
  56.  */
  57.  
  58. #ifdef notdef
  59. #include <sys/types.h>
  60. #include <sys/param.h>
  61. #include <sys/stat.h>
  62. #include <dirent.h>
  63. #include <ctype.h>
  64. typedef void * ptr_t;
  65. #endif
  66.  
  67. #define Char __Char
  68. #include "sh.h"
  69. #undef Char
  70. #undef QUOTE
  71. #undef TILDE
  72. #undef META
  73. #undef CHAR
  74. #undef ismeta
  75. #undef Strchr
  76.  
  77. #include <glob.h>
  78.  
  79. #ifndef S_ISDIR
  80. #define S_ISDIR(a)    (((a) & S_IFMT) == S_IFDIR)
  81. #endif
  82.  
  83. #if !defined(S_ISLNK) && defined(S_IFLNK)
  84. #define S_ISLNK(a)    (((a) & S_IFMT) == S_IFLNK)
  85. #endif
  86.  
  87. #if !defined(S_ISLNK) && !defined(lstat)
  88. #define lstat stat
  89. #endif
  90.  
  91. typedef unsigned short Char;
  92.  
  93. static    int     glob1         __P((Char *, glob_t *, int));
  94. static    int     glob2        __P((Char *, Char *, Char *, glob_t *, int));
  95. static    int     glob3        __P((Char *, Char *, Char *, Char *,
  96.                      glob_t *, int));
  97. static    int     globextend    __P((Char *, glob_t *));
  98. static    int     match        __P((Char *, Char *, Char *, int));
  99. static    int     compare    __P((const ptr_t, const ptr_t));
  100. static     DIR    *Opendir    __P((Char *));
  101. #ifdef S_IFLNK
  102. static    int     Lstat        __P((Char *, struct stat *));
  103. #endif
  104. static     Char     *Strchr        __P((Char *, int));
  105. #ifdef DEBUG
  106. static    void     qprintf    __P((Char *));
  107. #endif
  108.  
  109. #define    DOLLAR        '$'
  110. #define    DOT        '.'
  111. #define    EOS        '\0'
  112. #define    LBRACKET    '['
  113. #define    NOT        '!'
  114. #define ALTNOT        '^'
  115. #define    QUESTION    '?'
  116. #define    QUOTE        '\\'
  117. #define    RANGE        '-'
  118. #define    RBRACKET    ']'
  119. #define    SEP        '/'
  120. #define    STAR        '*'
  121. #define    TILDE        '~'
  122. #define    UNDERSCORE    '_'
  123.  
  124. #define    M_META        0x8000
  125. #define M_PROTECT    0x4000
  126. #define    M_MASK        0xffff
  127. #define    M_ASCII        0x00ff
  128.  
  129. #define    CHAR(c)        ((c)&M_ASCII)
  130. #define    META(c)        ((c)|M_META)
  131. #define    M_ALL        META('*')
  132. #define    M_END        META(']')
  133. #define    M_NOT        META('!')
  134. #define    M_ALTNOT    META('^')
  135. #define    M_ONE        META('?')
  136. #define    M_RNG        META('-')
  137. #define    M_SET        META('[')
  138. #define    ismeta(c)    (((c)&M_META) != 0)
  139.  
  140. /*
  141.  * Need to dodge two kernel bugs:
  142.  * opendir("") != opendir(".")
  143.  * NAMEI_BUG: on plain files trailing slashes are ignored in some kernels.
  144.  *            POSIX specifies that they should be ignored in directories.
  145.  */
  146.  
  147. static DIR *
  148. Opendir(str)
  149.     register Char *str;
  150. {
  151.     char    buf[MAXPATHLEN];
  152.     register char *dc = buf;
  153.  
  154.     if (!*str)
  155.     return (opendir("."));
  156.     while (*dc++ = *str++);
  157.     return (opendir(buf));
  158. }
  159.  
  160. #ifdef S_IFLNK
  161. static int
  162. Lstat(fn, sb)
  163.     register Char *fn;
  164.     struct stat *sb;
  165. {
  166.     char    buf[MAXPATHLEN];
  167.     register char *dc = buf;
  168.  
  169.     while (*dc++ = *fn++);
  170. # ifdef NAMEI_BUG
  171.     {
  172.     int     st;
  173.  
  174.     st = lstat(buf, sb);
  175.     if (*buf)
  176.         dc--;
  177.     return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st);
  178.     }
  179. # else
  180.     return (lstat(buf, sb));
  181. # endif    /* NAMEI_BUG */
  182. }
  183. #else
  184. #define Lstat Stat
  185. #endif /* S_IFLNK */
  186.  
  187. static int
  188. Stat(fn, sb)
  189.     register Char *fn;
  190.     struct stat *sb;
  191. {
  192.     char    buf[MAXPATHLEN];
  193.     register char *dc = buf;
  194.  
  195.     while (*dc++ = *fn++);
  196. #ifdef NAMEI_BUG
  197.     {
  198.     int     st;
  199.  
  200.     st = lstat(buf, sb);
  201.     if (*buf)
  202.         dc--;
  203.     return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st);
  204.     }
  205. #else
  206.     return (stat(buf, sb));
  207. #endif /* NAMEI_BUG */
  208. }
  209.  
  210. static Char *
  211. Strchr(str, ch)
  212.     Char *str;
  213.     int ch;
  214. {
  215.     do
  216.     if (*str == ch)
  217.         return (str);
  218.     while (*str++);
  219.     return (NULL);
  220. }
  221.  
  222. #ifdef DEBUG
  223. static void
  224. qprintf(s)
  225. Char *s;
  226. {
  227.     Char *p;
  228.  
  229.     for (p = s; *p; p++)
  230.     printf("%c", *p & 0xff);
  231.     printf("\n");
  232.     for (p = s; *p; p++)
  233.     printf("%c", *p & M_PROTECT ? '"' : ' ');
  234.     printf("\n");
  235.     for (p = s; *p; p++)
  236.     printf("%c", *p & M_META ? '_' : ' ');
  237.     printf("\n");
  238. }
  239. #endif /* DEBUG */
  240.  
  241. static int
  242. compare(p, q)
  243.     const ptr_t  p, q;
  244. {
  245.     return (strcmp(*(char **) p, *(char **) q));
  246. }
  247.  
  248. /*
  249.  * The main glob() routine: compiles the pattern (optionally processing
  250.  * quotes), calls glob1() to do the real pattern matching, and finally
  251.  * sorts the list (unless unsorted operation is requested).  Returns 0
  252.  * if things went well, nonzero if errors occurred.  It is not an error
  253.  * to find no matches.
  254.  */
  255. int
  256. glob(pattern, flags, errfunc, pglob)
  257.     const char *pattern;
  258.     int     flags;
  259.     int     (*errfunc) __P((char *, int));
  260.     glob_t *pglob;
  261. {
  262.     int     err, oldpathc;
  263.     Char *bufnext, *bufend, *compilebuf, m_not;
  264.     const unsigned char *compilepat, *patnext;
  265.     int     c, not;
  266.     Char patbuf[MAXPATHLEN + 1], *qpatnext;
  267.     int     no_match;
  268.  
  269.     patnext = (unsigned char *) pattern;
  270.     if (!(flags & GLOB_APPEND)) {
  271.     pglob->gl_pathc = 0;
  272.     pglob->gl_pathv = NULL;
  273.     if (!(flags & GLOB_DOOFFS))
  274.         pglob->gl_offs = 0;
  275.     }
  276.     pglob->gl_flags = flags & ~GLOB_MAGCHAR;
  277.     pglob->gl_errfunc = errfunc;
  278.     oldpathc = pglob->gl_pathc;
  279.     pglob->gl_matchc = 0;
  280.  
  281.     if (pglob->gl_flags & GLOB_ALTNOT) {
  282.     not = ALTNOT;
  283.     m_not = M_ALTNOT;
  284.     }
  285.     else {
  286.     not = NOT;
  287.     m_not = M_NOT;
  288.     }
  289.  
  290.     bufnext = patbuf;
  291.     bufend = bufnext + MAXPATHLEN;
  292.     compilebuf = bufnext;
  293.     compilepat = patnext;
  294.  
  295.     no_match = *patnext == not;
  296.     if (no_match)
  297.     patnext++;
  298.  
  299.     if (flags & GLOB_QUOTE) {
  300.     /* Protect the quoted characters */
  301.     while (bufnext < bufend && (c = *patnext++) != EOS) 
  302.         if (c == QUOTE) {
  303.         if ((c = *patnext++) == EOS) {
  304.             c = QUOTE;
  305.             --patnext;
  306.         }
  307.         *bufnext++ = c | M_PROTECT;
  308.         }
  309.         else
  310.         *bufnext++ = c;
  311.     }
  312.     else 
  313.     while (bufnext < bufend && (c = *patnext++) != EOS) 
  314.         *bufnext++ = c;
  315.     *bufnext = EOS;
  316.  
  317.     bufnext = patbuf;
  318.     qpatnext = patbuf;
  319.     /* we don't need to check for buffer overflow any more */
  320.     while ((c = *qpatnext++) != EOS) {
  321.     switch (c) {
  322.     case LBRACKET:
  323.         c = *qpatnext;
  324.         if (c == not)
  325.         ++qpatnext;
  326.         if (*qpatnext == EOS ||
  327.         Strchr(qpatnext + 1, RBRACKET) == NULL) {
  328.         *bufnext++ = LBRACKET;
  329.         if (c == not)
  330.             --qpatnext;
  331.         break;
  332.         }
  333.         pglob->gl_flags |= GLOB_MAGCHAR;
  334.         *bufnext++ = M_SET;
  335.         if (c == not)
  336.         *bufnext++ = m_not;
  337.         c = *qpatnext++;
  338.         do {
  339.         *bufnext++ = CHAR(c);
  340.         if (*qpatnext == RANGE &&
  341.             (c = qpatnext[1]) != RBRACKET) {
  342.             *bufnext++ = M_RNG;
  343.             *bufnext++ = CHAR(c);
  344.             qpatnext += 2;
  345.         }
  346.         } while ((c = *qpatnext++) != RBRACKET);
  347.         *bufnext++ = M_END;
  348.         break;
  349.     case QUESTION:
  350.         pglob->gl_flags |= GLOB_MAGCHAR;
  351.         *bufnext++ = M_ONE;
  352.         break;
  353.     case STAR:
  354.         pglob->gl_flags |= GLOB_MAGCHAR;
  355.         *bufnext++ = M_ALL;
  356.         break;
  357.     default:
  358.         *bufnext++ = CHAR(c);
  359.         break;
  360.     }
  361.     }
  362.     *bufnext = EOS;
  363. #ifdef DEBUG
  364.     qprintf(patbuf);
  365. #endif
  366.  
  367.     if ((err = glob1(patbuf, pglob, no_match)) != 0)
  368.     return (err);
  369.  
  370.     /*
  371.      * If there was no match we are going to append the pattern 
  372.      * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
  373.      * and the pattern did not contain any magic characters
  374.      * GLOB_NOMAGIC is there just for compatibility with csh.
  375.      */
  376.     if (pglob->gl_pathc == oldpathc && 
  377.     ((flags & GLOB_NOCHECK) || 
  378.      ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) {
  379.     if (!(flags & GLOB_QUOTE)) {
  380.         Char *dp = compilebuf;
  381.         const unsigned char *sp = compilepat;
  382.  
  383.         while (*dp++ = *sp++);
  384.     }
  385.     else {
  386.         /*
  387.          * copy pattern, interpreting quotes; this is slightly different
  388.          * than the interpretation of quotes above -- which should prevail?
  389.          */
  390.         while (*compilepat != EOS) {
  391.         if (*compilepat == QUOTE) {
  392.             if (*++compilepat == EOS)
  393.             --compilepat;
  394.         }
  395.         *compilebuf++ = (unsigned char) *compilepat++;
  396.         }
  397.         *compilebuf = EOS;
  398.     }
  399.     return (globextend(patbuf, pglob));
  400.     }
  401.     else if (!(flags & GLOB_NOSORT))
  402.     qsort((char *) (pglob->gl_pathv + pglob->gl_offs + oldpathc),
  403.           pglob->gl_pathc - oldpathc, sizeof(char *),
  404.           (int (*) __P((const void *, const void *))) compare);
  405.     return (0);
  406. }
  407.  
  408. static int
  409. glob1(pattern, pglob, no_match)
  410.     Char *pattern;
  411.     glob_t *pglob;
  412.     int     no_match;
  413. {
  414.     Char pathbuf[MAXPATHLEN + 1];
  415.  
  416.     /*
  417.      * a null pathname is invalid -- POSIX 1003.1 sect. 2.4.
  418.      */
  419.     if (*pattern == EOS)
  420.     return (0);
  421.     return (glob2(pathbuf, pathbuf, pattern, pglob, no_match));
  422. }
  423.  
  424. /*
  425.  * functions glob2 and glob3 are mutually recursive; there is one level
  426.  * of recursion for each segment in the pattern that contains one or
  427.  * more meta characters.
  428.  */
  429. static int
  430. glob2(pathbuf, pathend, pattern, pglob, no_match)
  431.     Char *pathbuf, *pathend, *pattern;
  432.     glob_t *pglob;
  433.     int     no_match;
  434. {
  435.     struct stat sbuf;
  436.     int anymeta;
  437.     Char *p, *q;
  438.  
  439.     /*
  440.      * loop over pattern segments until end of pattern or until segment with
  441.      * meta character found.
  442.      */
  443.     anymeta = 0;
  444.     for (;;) {
  445.     if (*pattern == EOS) {    /* end of pattern? */
  446.         *pathend = EOS;
  447.         if (Lstat(pathbuf, &sbuf))
  448.         return (0);
  449.  
  450.         if (((pglob->gl_flags & GLOB_MARK) &&
  451.          pathend[-1] != SEP) &&
  452.         (S_ISDIR(sbuf.st_mode)
  453. #ifdef S_IFLNK
  454.          || (S_ISLNK(sbuf.st_mode) &&
  455.              (Stat(pathbuf, &sbuf) == 0) &&
  456.              S_ISDIR(sbuf.st_mode))
  457. #endif
  458.          )) {
  459.         *pathend++ = SEP;
  460.         *pathend = EOS;
  461.         }
  462.         ++pglob->gl_matchc;
  463.         return (globextend(pathbuf, pglob));
  464.     }
  465.  
  466.     /* find end of next segment, copy tentatively to pathend */
  467.     q = pathend;
  468.     p = pattern;
  469.     while (*p != EOS && *p != SEP) {
  470.         if (ismeta(*p))
  471.         anymeta = 1;
  472.         *q++ = *p++;
  473.     }
  474.  
  475.     if (!anymeta) {        /* no expansion, do next segment */
  476.         pathend = q;
  477.         pattern = p;
  478.         while (*pattern == SEP)
  479.         *pathend++ = *pattern++;
  480.     }
  481.     else            /* need expansion, recurse */
  482.         return (glob3(pathbuf, pathend, pattern, p, pglob, no_match));
  483.     }
  484.     /* NOTREACHED */
  485. }
  486.  
  487.  
  488. static int
  489. glob3(pathbuf, pathend, pattern, restpattern, pglob, no_match)
  490.     Char *pathbuf, *pathend, *pattern, *restpattern;
  491.     glob_t *pglob;
  492.     int     no_match;
  493. {
  494.     extern int errno;
  495.     DIR    *dirp;
  496.     struct dirent *dp;
  497.     int     err;
  498.     Char m_not = (pglob->gl_flags & GLOB_ALTNOT) ? M_ALTNOT : M_NOT;
  499.  
  500.     *pathend = EOS;
  501.     errno = 0;
  502.  
  503.     if (!(dirp = Opendir(pathbuf)))
  504.     /* todo: don't call for ENOENT or ENOTDIR? */
  505.     if ((pglob->gl_errfunc && (*pglob->gl_errfunc) (pathbuf, errno)) ||
  506.         (pglob->gl_flags & GLOB_ERR))
  507.         return (GLOB_ABEND);
  508.     else
  509.         return (0);
  510.  
  511.     err = 0;
  512.  
  513.     /* search directory for matching names */
  514.     while ((dp = readdir(dirp))) {
  515.     register unsigned char *sc;
  516.     register Char *dc;
  517.  
  518.     /* initial DOT must be matched literally */
  519.     if (dp->d_name[0] == DOT && *pattern != DOT)
  520.         continue;
  521.     for (sc = (unsigned char *) dp->d_name, dc = pathend; *dc++ = *sc++;);
  522.     if (match(pathend, pattern, restpattern, m_not) == no_match) {
  523.         *pathend = EOS;
  524.         continue;
  525.     }
  526.     err = glob2(pathbuf, --dc, restpattern, pglob, no_match);
  527.     if (err)
  528.         break;
  529.     }
  530.     /* todo: check error from readdir? */
  531.     (void) closedir(dirp);
  532.     return (err);
  533. }
  534.  
  535.  
  536. /*
  537.  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
  538.  * add the new item, and update gl_pathc.
  539.  *
  540.  * This assumes the BSD realloc, which only copies the block when its size
  541.  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
  542.  * behavior.
  543.  *
  544.  * Return 0 if new item added, error code if memory couldn't be allocated.
  545.  *
  546.  * Invariant of the glob_t structure:
  547.  *    Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
  548.  *     gl_pathv points to (gl_offs + gl_pathc + 1) items.
  549.  */
  550. static int
  551. globextend(path, pglob)
  552.     Char *path;
  553.     glob_t *pglob;
  554. {
  555.     register char **pathv;
  556.     register int i;
  557.     unsigned int newsize;
  558.     char   *copy;
  559.     Char *p;
  560.  
  561.     newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
  562.     pathv = (char **) (pglob->gl_pathv ?
  563.                realloc((ptr_t) pglob->gl_pathv, newsize) :
  564.                malloc((size_t) newsize));
  565.     if (pathv == NULL)
  566.     return (GLOB_NOSPACE);
  567.  
  568.     if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
  569.     /* first time around -- clear initial gl_offs items */
  570.     pathv += pglob->gl_offs;
  571.     for (i = pglob->gl_offs; --i >= 0;)
  572.         *--pathv = NULL;
  573.     }
  574.     pglob->gl_pathv = pathv;
  575.  
  576.     for (p = path; *p++;);
  577.     if ((copy = (char *) malloc((size_t) (p - path))) != NULL) {
  578.     register char *dc = copy;
  579.     register Char *sc = path;
  580.  
  581.     while (*dc++ = *sc++);
  582.     pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
  583.     }
  584.     pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
  585.     return ((copy == NULL) ? GLOB_NOSPACE : 0);
  586. }
  587.  
  588.  
  589. /*
  590.  * pattern matching function for filenames.  Each occurrence of the *
  591.  * pattern causes a recursion level.
  592.  */
  593. static  int
  594. match(name, pat, patend, m_not)
  595.     register Char *name, *pat, *patend;
  596.     int m_not;
  597. {
  598.     int ok, negate_range;
  599.     Char c, k;
  600.  
  601.     while (pat < patend) {
  602.     c = *pat++;
  603.     switch (c & M_MASK) {
  604.     case M_ALL:
  605.         if (pat == patend)
  606.         return (1);
  607.         for (; *name != EOS; ++name) {
  608.         if (match(name, pat, patend, m_not))
  609.             return (1);
  610.         }
  611.         return (0);
  612.     case M_ONE:
  613.         if (*name++ == EOS)
  614.         return (0);
  615.         break;
  616.     case M_SET:
  617.         ok = 0;
  618.         if ((k = *name++) == EOS)
  619.         return (0);
  620.         if (negate_range = ((*pat & M_MASK) == m_not))
  621.         ++pat;
  622.         while (((c = *pat++) & M_MASK) != M_END) {
  623.         if ((*pat & M_MASK) == M_RNG) {
  624.             if (c <= k && k <= pat[1])
  625.             ok = 1;
  626.             pat += 2;
  627.         }
  628.         else if (c == k)
  629.             ok = 1;
  630.         }
  631.         if (ok == negate_range)
  632.         return (0);
  633.         break;
  634.     default:
  635.         if (*name++ != c)
  636.         return (0);
  637.         break;
  638.     }
  639.     }
  640.     return (*name == EOS);
  641. }
  642.  
  643. /* free allocated data belonging to a glob_t structure */
  644. void
  645. globfree(pglob)
  646.     glob_t *pglob;
  647. {
  648.     register int i;
  649.     register char **pp;
  650.  
  651.     if (pglob->gl_pathv != NULL) {
  652.     pp = pglob->gl_pathv + pglob->gl_offs;
  653.     for (i = pglob->gl_pathc; i--; ++pp)
  654.         if (*pp)
  655.         free((ptr_t) *pp), *pp = NULL;
  656.     free((ptr_t) pglob->gl_pathv), pglob->gl_pathv = NULL;
  657.     }
  658. }
  659.